package middleware

import (
	"fmt"
	"net/http"
	"peilian-api/app/global/common"
	"peilian-api/app/global/variable"
	"peilian-api/utils/tools"
	"time"

	"github.com/dgrijalva/jwt-go"
	"github.com/gin-gonic/gin"
	"github.com/mitchellh/mapstructure"
)

type CustomClaims struct {
	UserId   int64  `json:"userId"`
	UserName string `json:"userName"`
	RoleId   string `json:"roleId"`
	ENV      string `json:"env"`
	jwt.StandardClaims
}

func JWTAuth() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 查看是否含有token
		authToken := c.Request.Header.Get("AuthenticationToken")
		if authToken == "" {
			authToken = c.Query("AuthenticationToken")
		}
		if authToken == "AMiner123@" { //用于开发
			return
		}
		fullPath := c.FullPath()
		if len(authToken) == 0 {
			switch fullPath {
			case "/question/groups":
				return
			case "/practice/session/is_first", "/practice/feedback/evaluate":
				uid := c.GetHeader("X-User-Id")
				if uid != "" {
					c.Set("uid", uid)
					return
				}
			}
		}
		if len(authToken) == 0 {
			c.JSON(http.StatusOK, gin.H{
				"code": 401,
				"data": struct{}{},
				"msg":  "fetch request token fail",
			})
			c.Abort()
			return
		}

		tk, claims, err := tools.ParseToken(authToken)
		if err != nil || !tk.Valid || claims.UserId == 0 || variable.Env != claims.Env {
			if variable.Env != "local" {
				c.JSON(http.StatusOK, gin.H{
					"code": 401,
					"data": struct{}{},
					"msg":  "request token auth fail",
				})
				c.Abort()
				return
			}
		}
		expires_at := claims.ExpiresAt
		if time.Now().Unix() > expires_at {
			c.JSON(http.StatusOK, gin.H{
				"code": 401,
				"data": struct{}{},
				"msg":  "request token hash expired, please login again",
			})
			c.Abort()
			return
		}
		// 手机号登录
		sto := tools.Sto{}
		mapstructure.Decode(claims.St, &sto)

		redisKey := ""
		// if claims.Type == tools.TypePhone {
		// 	redisKey = fmt.Sprintf(common.RedisPhoneKey, sto.Phone)
		// } else if claims.Type == tools.TypeAccount { // 后台登录
		// 	redisKey = fmt.Sprintf(common.RedisAccountKey, sto.AccountName)
		// } else if claims.Type == tools.TypeSnoAccount {
		// 	if sto.Phone == "" {
		// 		redisKey = fmt.Sprintf(common.RedisPhoneKey, fmt.Sprintf("%s_%s", sto.School, sto.Sno))
		// 	} else {
		// 		redisKey = fmt.Sprintf(common.RedisPhoneKey, sto.Phone)
		// 	}
		// }
		if claims.Type == tools.TypeAccount {
			redisKey = fmt.Sprintf(common.RedisAccountKey, sto.AccountName)
		} else {
			redisKey = fmt.Sprintf(common.RedisUserLoginKey, sto.Id)
		}
		sc := variable.DB.Redis.Get(redisKey)
		v, err := sc.Result()
		if err != nil && sc.Err() != nil && v != tools.Md5DataString(authToken) {
			c.JSON(http.StatusOK, gin.H{
				"code": 401,
				"data": struct{}{},
				"msg":  "request token hash expired, please login again",
			})
			c.Abort()
			return
		}

		// 非游客账户-校验服务是否过期
		//if sto.Type != tables.UserTypeAnonymous {
		//	scr := variable.DB.Redis.Get(fmt.Sprintf(common.RedisAgentIsTimeoutKey, sto.AgentId))
		//	str, err := scr.Result()
		//	if err != nil {
		//		c.JSON(http.StatusOK, gin.H{
		//			"code": 40001,
		//			"data": struct{}{},
		//			"msg":  "您的服务未生效，请联系管理员",
		//		})
		//		c.Abort()
		//		return
		//	}
		//	endStamp, _ := strconv.ParseInt(str, 10, 64)
		//	if endStamp-time.Now().Unix() < common.AgentTimeKey {
		//		c.JSON(http.StatusOK, gin.H{
		//			"code": 40001,
		//			"data": struct{}{},
		//			"msg":  "您的服务已到期，请联系管理员",
		//		})
		//		c.Abort()
		//		return
		//	}
		//}

		// 将当前用户信息保存在请求上下中
		c.Set("uid", claims.UserId)

		// 记得需要的话是登录请求
		c.Set("sto", claims.St)

		// 用户类型
		c.Set("utype", sto.Type)

		// 角色id
		c.Set("rid", sto.RoleId)

		// 客户id
		c.Set("aid", sto.AgentId)

		// 登录的来源
		c.Set("source", sto.Source)

		c.Next()
	}
}
